﻿#region Copyright and License Notice
// Copyright (C)2010-2016 - Rob Levine and other contributors
// http://configgen.codeplex.com
// 
// This file is part of ConfigGen.
// 
// ConfigGen is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// ConfigGen is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License and 
// the GNU Lesser General Public License along with ConfigGen.  
// If not, see <http://www.gnu.org/licenses/>
#endregion

using System;
using System.Data;
using System.Reflection;
using ConfigGen.Core.SettingsLoader;
using ConfigGen.Utilities.Extensions.System.Reflection;
using Moq;
using NUnit.Framework;

namespace ConfigGen.Core.Tests.SettingsLoader
{
    [TestFixture]
    public class ExcelSettingsLoaderTests
    {
        [Test]
        public void Ctor001_BadArgs()
        {
            var mockHeaderProcessor = new Mock<ISpreadsheetHeaderProcessor>();
            var mockDataProcessor = new Mock<ISpreadsheetDataProcessor>();
            var mockExcelSpreadsheetLoader = new Mock<IExcelFileLoader>();
            var mockSpreadsheetPreferencesLoader = new Mock<ISpreadsheetPreferencesLoader>();
            Assert.Throws<ArgumentNullException>(
                () => new ExcelSettingsLoader(null, mockDataProcessor.Object, mockExcelSpreadsheetLoader.Object, mockSpreadsheetPreferencesLoader.Object),
                "Null 1st arg should have thrown");

            Assert.Throws<ArgumentNullException>(
                () => new ExcelSettingsLoader(mockHeaderProcessor.Object, null, mockExcelSpreadsheetLoader.Object, mockSpreadsheetPreferencesLoader.Object), 
                "Null 2nd arg should have thrown");

            Assert.Throws<ArgumentNullException>(
                () => new ExcelSettingsLoader(mockHeaderProcessor.Object, mockDataProcessor.Object, null, mockSpreadsheetPreferencesLoader.Object), 
                "Null 3rd arg should have thrown");

            Assert.Throws<ArgumentNullException>(
               () => new ExcelSettingsLoader(mockHeaderProcessor.Object, mockDataProcessor.Object, mockExcelSpreadsheetLoader.Object, null),
               "Null 4th arg should have thrown");
        }

        [Test]
        public void LoadSettings001_NullArgs()
        {
            var mockHeaderProcessor = new Mock<ISpreadsheetHeaderProcessor>();
            var mockDataProcessor = new Mock<ISpreadsheetDataProcessor>();
            var mockSpreadsheetLoader = new Mock<IExcelFileLoader>();
            var mockSpreadsheetPreferencesLoader = new Mock<ISpreadsheetPreferencesLoader>();
            var itemUnderTest = new ExcelSettingsLoader(
                mockHeaderProcessor.Object, 
                mockDataProcessor.Object, 
                mockSpreadsheetLoader.Object,
                mockSpreadsheetPreferencesLoader.Object);

            Assert.Throws<ArgumentNullException>(() => itemUnderTest.LoadSettings(null));
        }

        [Test]
        public void LoadSettings002_WrongNumberOfArgs()
        {
            var mockHeaderProcessor = new Mock<ISpreadsheetHeaderProcessor>();
            var mockDataProcessor = new Mock<ISpreadsheetDataProcessor>();
            var mockSpreadsheetLoader = new Mock<IExcelFileLoader>();
            var mockSpreadsheetPreferencesLoader = new Mock<ISpreadsheetPreferencesLoader>();
            var itemUnderTest = new ExcelSettingsLoader(
                mockHeaderProcessor.Object,
                mockDataProcessor.Object,
                mockSpreadsheetLoader.Object,
                mockSpreadsheetPreferencesLoader.Object);

            Assert.Throws<ArgumentException>(() => itemUnderTest.LoadSettings(new string[0]), "Zero args should throw an exception");
            Assert.Throws<ArgumentException>(() => itemUnderTest.LoadSettings(new[] { "1", "2", "3" }), "More than two args should throw an exception");
        }

        [Test]
        public void LoadSettings003_SpecifiedWorksheetNotFound()
        {
            var mockHeaderProcessor = new Mock<ISpreadsheetHeaderProcessor>();
            var mockDataProcessor = new Mock<ISpreadsheetDataProcessor>();
            var mockSpreadsheetLoader = new Mock<IExcelFileLoader>();
            mockSpreadsheetLoader
                .Setup(l => l.GetSettingsDataSet(It.IsAny<string>()))
                .Returns(new DataSet());
            var mockSpreadsheetPreferencesLoader = new Mock<ISpreadsheetPreferencesLoader>();
            mockSpreadsheetPreferencesLoader
                .Setup(l => l.GetSpreadsheetPreferences(It.IsAny<DataSet>()))
                .Returns(SpreadsheetPreferences.GetDefaultPreferences);

            var itemUnderTest = new ExcelSettingsLoader(
                mockHeaderProcessor.Object,
                mockDataProcessor.Object,
                mockSpreadsheetLoader.Object,
                mockSpreadsheetPreferencesLoader.Object);
            using (var testFile = Assembly.GetExecutingAssembly().GetEmbeddedResourceFile("SettingsLoader.SampleFiles.App.Config.Settings.xlsx", "App.Config.Settings.xlsx"))
            {
                var args = new[] { testFile.FullName, "NonExistentWorksheet" };
                Assert.Throws<ArgumentException>(() => itemUnderTest.LoadSettings(args));
            }
        }

        /// <summary>
        /// Asserts that the correct args are passed to the excel spreadsheet loader (the full filename) and also that LoadSettings
        /// defaults to the "Settings" worksheet name if none is specified.
        /// </summary>
        [Test]
        public void LoadSettings004_ArgsPassedToLoaderAndDefaultWorksheetName()
        {
            var mockHeaderProcessor = new Mock<ISpreadsheetHeaderProcessor>();
            var mockDataProcessor = new Mock<ISpreadsheetDataProcessor>();
            string argPassedToLoader = null;
            var mockSpreadsheetLoader = new Mock<IExcelFileLoader>();
            var dataSet = new DataSet();
            dataSet.Tables.Add("Settings");
            mockSpreadsheetLoader
                .Setup(l => l.GetSettingsDataSet(It.IsAny<string>()))
                .Callback((string s) => argPassedToLoader = s)
                .Returns(dataSet);
            var mockSpreadsheetPreferencesLoader = new Mock<ISpreadsheetPreferencesLoader>();
            mockSpreadsheetPreferencesLoader
                .Setup(l => l.GetSpreadsheetPreferences(It.IsAny<DataSet>()))
                .Returns(SpreadsheetPreferences.GetDefaultPreferences);

            var itemUnderTest = new ExcelSettingsLoader(
                mockHeaderProcessor.Object,
                mockDataProcessor.Object,
                mockSpreadsheetLoader.Object,
                mockSpreadsheetPreferencesLoader.Object);

            using (
                var testFile =
                    Assembly.GetExecutingAssembly().GetEmbeddedResourceFile(
                        "SettingsLoader.SampleFiles.App.Config.Settings_DefaultNamedWorksheet.xlsx",
                        "App.Config.Settings.xlsx"))
            {
                var args = new[] {testFile.FullName};
                itemUnderTest.LoadSettings(args);

                Assert.AreEqual(testFile.FullName, argPassedToLoader,
                                "Incorrect filename passed to GetSettingsDataSet call.");
            }
        }

        [Test]
        public void LoadSettings006_WorksheetNameSpecified()
        {
            var mockHeaderProcessor = new Mock<ISpreadsheetHeaderProcessor>();
            var mockDataProcessor = new Mock<ISpreadsheetDataProcessor>();
            var mockSpreadsheetLoader = new Mock<IExcelFileLoader>();
            var dataSet = new DataSet();
            dataSet.Tables.Add("Sheet1");
            mockSpreadsheetLoader
              .Setup(l => l.GetSettingsDataSet(It.IsAny<string>()))
              .Returns(dataSet);

            var mockSpreadsheetPreferencesLoader = new Mock<ISpreadsheetPreferencesLoader>();
            mockSpreadsheetPreferencesLoader
                .Setup(l => l.GetSpreadsheetPreferences(It.IsAny<DataSet>()))
                .Returns(SpreadsheetPreferences.GetDefaultPreferences);

            var itemUnderTest = new ExcelSettingsLoader(
                mockHeaderProcessor.Object,
                mockDataProcessor.Object,
                mockSpreadsheetLoader.Object,
                mockSpreadsheetPreferencesLoader.Object);

            using (var testFile = Assembly.GetExecutingAssembly().GetEmbeddedResourceFile("SettingsLoader.SampleFiles.App.Config.Settings.xlsx", "App.Config.Settings.xlsx"))
            {
                var args = new[] { testFile.FullName, "Sheet1" };
                var settings = itemUnderTest.LoadSettings(args);
            }
        }
    }
}
